`timescale 1ns / 1ps

module fishnet_123
#(
    parameter N_IN      = 3,
    parameter N_OT      = 1,
    parameter BIT_IM    = 8
)
(
    input   clk,
    input   rst,
    
    input   i_vld,
    output  i_rdy,
    input   [N_IN*BIT_IM-1 : 0]      i_data,
    
    output  o_vld,
    input   o_rdy,
    output  [N_OT*BIT_IM-1 : 0]      o_data
);

localparam ROW_0 = 360;
localparam ROW_1 = 160;
localparam ROW_2 = ROW_1 / 2;
localparam ROW_3 = ROW_2 / 2;
localparam ROW_4 = ROW_3 / 2;

localparam COL_0 = 640;
localparam COL_1 = 320;
localparam COL_2 = COL_1 / 2;
localparam COL_3 = COL_2 / 2;
localparam COL_4 = COL_3 / 2;

localparam NCH_0 = 3;
localparam NCH_1 = 48;
localparam NCH_2 = 96;
localparam NCH_3 = 192;
localparam NCH_4 = 384;
localparam NCH_5 = 512;
localparam NCH_6 = 4 * NCH_3 + NCH_5;   // 1280
localparam NCH_7 = 96;
localparam NCH_8 = 10;

localparam NIO_1 = 4;
localparam NIO_2 = 2;
localparam NIO_3 = 1;

wire l1_rdy;
wire l1_vld;
wire [NIO_1 * BIT_IM - 1 : 0] l1_data;

dwpw_layer #(
    .N_IN          ( N_IN          ),
    .N_OT          ( NIO_1         ),
    .N_ICH         ( NCH_0         ),
    .N_OCH         ( NCH_1         ),
    .BIT_IM        ( 8             ),
    .BIT_WT        ( 5             ),
    .BIT_CV        ( 16            ),
    .BIT_NB        ( 16            ),
    .BIT_NM        ( 16            ),
    .ROW           ( ROW_1         ),
    .COL           ( COL_1         ),
    .DW_INW        ( 3             ),
    .DW_ACT        ( 1             ),
    .DW_PAD        ( 128           ),
    .DWCV_PE       ( "LUT"         ),
    .DWET_FILE     ( "L0_DW.mem"   ),
    .DWET_TYPE     ( "distributed" ),
    .DWET_LATENCY  ( 1             ),
    .DBUF_TYPE     ( "block"       ),
    .DBUF_LATENCY  ( 2             ),
    .DNORM_PE      ( "LUT"         ),
    .DNORM_FILE    ( "L0_BM.mem"   ),
    .DNORM_TYPE    ( "distributed" ),
    .DNORM_LATENCY ( 1             ),
    .PW_INH        ( 1             ),
    .PW_INW        ( 3             ),
    .PW_OUT        ( 4             ),
    .PW_ACT        ( 4             ),
    .PWCV_PE       ( "LUT"         ),
    .PWET_FILE     ("L1_PW_old.mem"),
    .PWET_TYPE     ( "distributed" ),
    .PWET_LATENCY  ( 1             ),
    .PBUF_TYPE     ( "register"    ),
    .PBUF_LATENCY  ( 1             ),
    .PNORM_PE      ( "DSP"         ),
    .PNORM_FILE    ( "L1_BM.mem"   ),
    .PNORM_TYPE    ( "distributed" ),
    .PNORM_LATENCY ( 1             ),
    .PFIFO_TYPE    ( "none"        ),
    .PFIFO_LATENCY ( 0             )
) inst_dwpw_1 (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   (  i_rdy   ),
    .i_vld                   (  i_vld   ),
    .i_data                  (  i_data  ),

    .o_rdy                   ( l1_rdy   ),
    .o_vld                   ( l1_vld   ),
    .o_data                  ( l1_data  )
);

wire p1_rdy;
wire p1_vld;
wire [NIO_1 * BIT_IM - 1 : 0] p1_data;

maxpool_layer #(
    .N_IO  ( NIO_1    ),
    .N_CH  ( NCH_1    ),
    .N_COL ( COL_1    ),
    .BIT   ( BIT_IM   )
) inst_pool_1 (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( l1_rdy   ),
    .i_vld                   ( l1_vld   ),
    .i_data                  ( l1_data  ),

    .o_rdy                   ( p1_rdy   ),
    .o_vld                   ( p1_vld   ),
    .o_data                  ( p1_data  )
);

wire l2_rdy;
wire l2_vld;
wire [NIO_2 * BIT_IM - 1 : 0] l2_data;

dwpw_layer #(
    .N_IN          ( NIO_1         ),
    .N_OT          ( NIO_2         ),
    .N_ICH         ( NCH_1         ),
    .N_OCH         ( NCH_2         ),
    .BIT_IM        ( 8             ),
    .BIT_WT        ( 5             ),
    .BIT_CV        ( 16            ),
    .BIT_NB        ( 16            ),
    .BIT_NM        ( 16            ),
    .ROW           ( ROW_2         ),
    .COL           ( COL_2         ),
    .DW_INW        ( 12            ),
    .DW_ACT        ( 1             ),
    .DW_PAD        ( 0             ),
    .DWCV_PE       ( "LUT"         ),
    .DWET_FILE     ( "L2_DW.mem"   ),
    .DWET_TYPE     ( "distributed" ),
    .DWET_LATENCY  ( 1             ),
    .DBUF_TYPE     ( "block"       ),
    .DBUF_LATENCY  ( 2             ),
    .DNORM_PE      ( "LUT"         ),
    .DNORM_FILE    ( "L2_BM.mem"   ),
    .DNORM_TYPE    ( "distributed" ),
    .DNORM_LATENCY ( 1             ),
    .PW_INH        ( 4             ),
    .PW_INW        ( 4             ),
    .PW_OUT        ( 6             ),
    .PW_ACT        ( 2             ),
    .PWCV_PE       ( "DSP"         ),
    .PWET_FILE     ( "L3_PW.mem"   ),
    .PWET_TYPE     ( "block"       ),
    .PWET_LATENCY  ( 2             ),
    .PBUF_TYPE     ( "distributed" ),
    .PBUF_LATENCY  ( 1             ),
    .PNORM_PE      ( "DSP"         ),
    .PNORM_FILE    ( "L3_BM.mem"   ),
    .PNORM_TYPE    ( "distributed" ),
    .PNORM_LATENCY ( 1             ),
    .PFIFO_TYPE    ( "block"       ),
    .PFIFO_LATENCY ( 2             )
) inst_dwpw_2 (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( p1_rdy   ),
    .i_vld                   ( p1_vld   ),
    .i_data                  ( p1_data  ),

    .o_rdy                   ( l2_rdy   ),
    .o_vld                   ( l2_vld   ),
    .o_data                  ( l2_data  )
);

wire p2_rdy;
wire p2_vld;
wire [NIO_2 * BIT_IM - 1 : 0] p2_data;

maxpool_layer #(
    .N_IO  ( NIO_2    ),
    .N_CH  ( NCH_2    ),
    .N_COL ( COL_2    ),
    .BIT   ( BIT_IM   )
) inst_pool_2 (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( l2_rdy   ),
    .i_vld                   ( l2_vld   ),
    .i_data                  ( l2_data  ),

    .o_rdy                   ( p2_rdy   ),
    .o_vld                   ( p2_vld   ),
    .o_data                  ( p2_data  )
);

wire l3_rdy;
wire l3_vld;
wire [NIO_3 * BIT_IM - 1 : 0] l3_data;

dwpw_layer #(
    .N_IN          ( NIO_2         ),
    .N_OT          ( NIO_3         ),
    .N_ICH         ( NCH_2         ),
    .N_OCH         ( NCH_3         ),
    .BIT_IM        ( 8             ),
    .BIT_WT        ( 5             ),
    .BIT_CV        ( 16            ),
    .BIT_NB        ( 16            ),
    .BIT_NM        ( 16            ),
    .ROW           ( ROW_3         ),
    .COL           ( COL_3         ),
    .DW_INW        ( 6             ),
    .DW_ACT        ( 1             ),
    .DW_PAD        ( 0             ),
    .DWCV_PE       ( "LUT"         ),
    .DWET_FILE     ( "L4_DW.mem"   ),
    .DWET_TYPE     ( "block"       ),
    .DWET_LATENCY  ( 2             ),
    .DBUF_TYPE     ( "block"       ),
    .DBUF_LATENCY  ( 2             ),
    .DNORM_PE      ( "LUT"         ),
    .DNORM_FILE    ( "L4_BM.mem"   ),
    .DNORM_TYPE    ( "block"       ),
    .DNORM_LATENCY ( 2             ),
    .PW_INH        ( 4             ),
    .PW_INW        ( 4             ),
    .PW_OUT        ( 6             ),
    .PW_ACT        ( 1             ),
    .PWCV_PE       ( "DSP"         ),
    .PWET_FILE     ( "L5_PW.mem"   ),
    .PWET_TYPE     ( "block"       ),
    .PWET_LATENCY  ( 2             ),
    .PBUF_TYPE     ( "distributed" ),
    .PBUF_LATENCY  ( 1             ),
    .PNORM_PE      ( "LUT"         ),
    .PNORM_FILE    ( "L5_BM.mem"   ),
    .PNORM_TYPE    ( "block"       ),
    .PNORM_LATENCY ( 2             ),
    .PFIFO_TYPE    ( "block"       ),
    .PFIFO_LATENCY ( 2             )
) inst_dwpw_3 (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .i_rdy                   ( p2_rdy   ),
    .i_vld                   ( p2_vld   ),
    .i_data                  ( p2_data  ),

    .o_rdy                   ( l3_rdy   ),
    .o_vld                   ( l3_vld   ),
    .o_data                  ( l3_data  )
);

assign l3_rdy = o_rdy;
assign o_vld = l3_vld;
assign o_data = l3_data;

endmodule
